﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Web.Configuration;
using System.Web.Http;
using System.Threading;
using System.Threading.Tasks;
using RequireHttps;
using DeviceModel;
using HubClientHandler;

namespace DeviceXApp.Controllers
{
    public class DeviceController : ApiController
    {
        class Threshold
        {
            public int UpperLimit { get; private set; }
            public DeviceStatus Status { get; private set; }

            public Threshold(string s)
            {
                var ss = s.Split(',');
                switch (ss[0].ToLower())
                {
                    case "ok":      Status = DeviceStatus.Ok; break;
                    case "warning": Status = DeviceStatus.Warning; break;
                    case "error":   Status = DeviceStatus.Error; break;
                    default:        Status = DeviceStatus.NoData; break;
                }

                UpperLimit = int.Parse(ss[1]);
            }
        }

        private static HubClient hubClient;
        private static List<Threshold> lstThreshold;
        private static ConcurrentDictionary<int, DateTime> cdctLastUpdateTime = new ConcurrentDictionary<int, DateTime>();
        private static Timer timerCheckIdle;

        public static void Configure()
        {
            hubClient = new HubClient(WebConfigurationManager.AppSettings["DashboardUri"], "ConnectivityHub");

            var lstTempThreshold = new List<Threshold>();
            foreach (string s in WebConfigurationManager.AppSettings["Thresholds"].Split('|'))
            {
                string st = null;
                if (!string.IsNullOrEmpty(st = s.Replace(" ", string.Empty)))
                    lstTempThreshold.Add(new Threshold(st));
            }

            lstThreshold = lstTempThreshold.OrderBy(t => t.UpperLimit).ToList();

            int idleTimeIntervalInSec = int.Parse(WebConfigurationManager.AppSettings["IdleTimeIntervalInSec"]);
            var idleTimeInterval = new TimeSpan(0, 0, idleTimeIntervalInSec);

            timerCheckIdle = new Timer(_ => 
                                    {
                                        try
                                        {
                                            foreach (var deviceId in cdctLastUpdateTime.Keys)
                                                if (DateTime.Now - cdctLastUpdateTime[deviceId] > idleTimeInterval)
                                                    CallDashboardHub("SetDeviceStatus", deviceId, (int)DeviceStatus.NoData);
                                        }
                                        catch (Exception e)
                                        {
                                            // Writing to log
                                        }
                                    }, 
                                    null, idleTimeIntervalInSec / 2, idleTimeIntervalInSec / 2);
        }

        public DeviceController() 
        {
        }

        [HttpGet]
        [RequireHttps]
        [Route("api/RegisterDevice/{deviceId}/{deviceType}/{deviceName}/{description}/{deviceSpecificData}")]
        public int RegisterDevice(int deviceId, string deviceType, string deviceName, string description, string deviceSpecificData)
        {
            cdctLastUpdateTime[deviceId] = DateTime.Now;

            CallDashboardHub("RegisterDeviceWithDashboard", 
                             new DeviceInfo { Id = deviceId, DeviceType = deviceType, Name = deviceName, Description = description, DeviceSpecificData = deviceSpecificData });
  
            return deviceId;
        }

        [HttpGet]
        [RequireHttps]
        [Route("api/DeviceData/{deviceId}/{data}")]
        public IHttpActionResult DeviceData(int deviceId, string data)
        {
            try
            {
                DeviceStatus status = DeviceStatus.NoData;
                int value;
                if (int.TryParse(data, out value))
                    foreach (var t in lstThreshold)
                        if (t.UpperLimit >= value)
                        {
                            status = t.Status;
                            cdctLastUpdateTime[deviceId] = DateTime.Now;
                            break;
                        }

                CallDashboardHub("SetDeviceStatus", deviceId, (int)status);
            }
            catch (Exception e)
            {
                // Writing to log
            }

            return Ok();
        }

        private static void CallDashboardHub(string methodName, params object[] obs)
        {
            Task.Factory.StartNew(() =>
                {
                    lock (typeof(DeviceController))
                        hubClient.HubProxy.Invoke(methodName, obs);
                });
        }
    }
}
